//package declaration
package pxgrid_utils;

//imports
import third_party_utils.Base64;
import java.io.*;
import java.util.*;
import java.util.regex.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import pxgrid_entities.*;


/**
 * PXUtils
 * A class to provide commonly used utility methods to other classes.
 * 
 * @author Mark Bate
 */
public class PXUtils {
    
    /**
     * Base64 encodes a file.
     * Essentially it wraps the method in Base64 class
     * @param fileName String the file to encode
     * @return String the Base64 encoded string
     */
    public static String base64EncodeFile(String fileName) {
        return Base64.encodeFromFile(fileName);
    }
    
    /**
     * Reads a file to a String
     * @param filepath String the path to the file to read
     * @return String the file as a String
     */
    public static String fileToString(String filepath) {
      try {
          File file = new File(filepath);
          String file_contents = "";
          if (file.isFile()) {
              
              FileReader fr = new FileReader(file);
              BufferedReader br = new BufferedReader (fr);
              
              while(br.read() != -1) {
                  String line = br.readLine();
                  file_contents += line+"\n";
                  
              }
              br.close(); 
              fr.close();
          }
          return file_contents;
          
      } catch(Exception ex) {
          return "Failed";
      }  
  }
    
    
    /**
     * Extracts the Metadata from the MTZ file
     * @param filepath String the path to the MTZ file
     * @return ArrayList an ArrayList containing the meta data
     */
    public static ArrayList extractMetaDataFromMTZFile(String filepath) {
        
        ArrayList meta = new ArrayList();
        
      try {
          File file = new File(filepath);
          String file_contents = "";
          if (file.isFile()) {
              
              FileReader fr = new FileReader(file);
              BufferedReader br = new BufferedReader (fr);
              
              while(br.read() != -1) {
                  String line = br.readLine();
                  if(line.toUpperCase().contains("VERS MTZ")) {
                      file_contents += line+"\n";
                  }
              }
              br.close(); 
              fr.close();
              
              int meta_data_start = file_contents.indexOf("VERS MTZ");
              
              String meta_data = file_contents.substring(meta_data_start);
              
              List meta_list = split(meta_data, 80);
              meta = new ArrayList(meta_list);
              
          }
          
          return meta;
          
      } catch(Exception ex) {
          return meta;
      }  
    }
    
    //Mark doesn't even know his own code!
    public static List split(String str, int maxLength) {
		Pattern p = Pattern.compile(".{1," + maxLength + "}");
		Matcher m = p.matcher(str);
		List<String> result = new ArrayList<String>();
		while (m.find()) {
			result.add(m.group());
		}
		return result;
	}
    

    /**
     * Convert a file to an ArrayList
     * @param filepath String the file to open
     * @return ArrayList the contents of the file, line by line in an ArrayList
     */
    public static ArrayList fileToArrayList(String filepath) {
      
        ArrayList file_contents = new ArrayList();
      try {
          File file = new File(filepath);
          
          if (file.isFile()) {
              
              FileReader fr = new FileReader(file);
              BufferedReader br = new BufferedReader (fr);

              while(br.read() != -1) {
                  file_contents.add(br.readLine());
              }
              br.close(); 
              fr.close();
          }
          
      } catch(Exception ex) {
        //might need to handle something here?
      } 
        
        return file_contents;
  }
    
    /**
     * gets the contents of a directory into an ArrayList
     * @param directory String the directory to list contents of
     * @return ArrayList contains the directory contents
     */
    public static ArrayList getDirectoryContentsAsArrayList(String directory) {
        String[] contents =  new File(directory).list();
        ArrayList dir_contents = new ArrayList();
        
        for(int i=0; i < contents.length; i++) {
            dir_contents.add(contents[i]);
        }
        
        return dir_contents;
        
    }
    
    /**
     * parses an XML file that describes a grid
     * @param fileName String the XML file to open
     * @return Map a map of information about the grid
     */
    public static Map parseGridXML(String fileName) {
        Map gridMap = new HashMap();

        try {
            File file = new File(fileName);
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(file);
            doc.getDocumentElement().normalize();

            NodeList nodeLst = doc.getElementsByTagName("grid");

            for (int s = 0; s < nodeLst.getLength(); s++) {

                Node fstNode = nodeLst.item(s);

                if (fstNode.getNodeType() == Node.ELEMENT_NODE) {

                    String display_name = ((Element) fstNode).getElementsByTagName("display_name").item(0).getChildNodes().item(0).getNodeValue();
                    
                    String host = ((Element) fstNode).getElementsByTagName("host").item(0).getChildNodes().item(0).getNodeValue();

                    String auth_method = ((Element) fstNode).getElementsByTagName("auth_method").item(0).getChildNodes().item(0).getNodeValue();

                    String password = ((Element) fstNode).getElementsByTagName("password").item(0).getChildNodes().item(0).getNodeValue();
                    
                    boolean available = Boolean.parseBoolean(((Element) fstNode).getElementsByTagName("available").item(0).getChildNodes().item(0).getNodeValue());

                    int grid_id = Integer.parseInt(((Element) fstNode).getElementsByTagName("grid_id").item(0).getChildNodes().item(0).getNodeValue());

                    gridMap.put(display_name, new PXGrid(display_name, host, auth_method, password, grid_id, available));
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return gridMap;
    }
    
    /**
     * creates a PXSubmission instance from a PXSubmission.xml file
     * @param fileName String the PXSubmission.xml file
     * @return PXSubmission a new instance containing all the details from the 
     * XML file
     */
    public static PXSubmission createPXSubmissionEntityFromXML(String fileName) {
        PXSubmission submission = new PXSubmission();
        
        try {
            File file = new File(fileName);
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(file);
            doc.getDocumentElement().normalize();

            NodeList nodeLst = doc.getElementsByTagName("job");

            for (int s = 0; s < nodeLst.getLength(); s++) {

                Node fstNode = nodeLst.item(s);

                if (fstNode.getNodeType() == Node.ELEMENT_NODE) {

                    String job_name = ((Element) fstNode).getElementsByTagName("job_name").item(0).getChildNodes().item(0).getNodeValue();
                    String input_mtz = ((Element) fstNode).getElementsByTagName("input_mtz").item(0).getChildNodes().item(0).getNodeValue();
                    String input_pdb = ((Element) fstNode).getElementsByTagName("input_pdb").item(0).getChildNodes().item(0).getNodeValue();
                    String space_group = ((Element) fstNode).getElementsByTagName("space_group").item(0).getChildNodes().item(0).getNodeValue();
                    double rmsd = Double.parseDouble(((Element) fstNode).getElementsByTagName("rmsd").item(0).getChildNodes().item(0).getNodeValue());
                    String grid_type = ((Element) fstNode).getElementsByTagName("grid_type").item(0).getChildNodes().item(0).getNodeValue();
                    String grid_display_name = ((Element) fstNode).getElementsByTagName("grid_display_name").item(0).getChildNodes().item(0).getNodeValue();
                    int grid_job_id = Integer.parseInt(((Element) fstNode).getElementsByTagName("grid_job_id").item(0).getChildNodes().item(0).getNodeValue());
                    
                    PXJob job = new PXJob();
                    
                    job.setJobName(job_name);
                    job.setInputMTZ(input_mtz);
                    job.setInputPDB(input_pdb);
                    job.setSpaceGroup(space_group);
                    job.setRMSD(rmsd);
                    job.setGridType(grid_type);
                    job.setGridController(grid_display_name);
                    job.setGridJobID(grid_job_id);
                    
                    submission.addJob(job);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        
        
        return submission;
    }
    
    /**
     * reads the location of the data_store from the server_config.xml
     * @return String the data_store location
     */
    public static String getDataStoreFromServerConfigXML() {
        Map configMap = new HashMap();
        String filename = "/mrconfig/server_config.xml";
        String data_store = "";

        try {
            File file = new File(filename);
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(file);
            doc.getDocumentElement().normalize();

            NodeList nodeLst = doc.getElementsByTagName("server_config");

            for (int s = 0; s < nodeLst.getLength(); s++) {

                Node fstNode = nodeLst.item(s);

                if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
                    data_store = ((Element) fstNode).getElementsByTagName("data_store").item(0).getChildNodes().item(0).getNodeValue();
                }
            }
            
            
            return data_store;
        } catch (Exception e) {
            return e.getMessage();
        }

    }
}
